/*  

* Copyright (C) 2013 - 2016 Xilinx, Inc
*
*   This program is free software; you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation; either version 2 of the License, or
*   (at your option) any later version.

*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License along
*   with this program. If not, see <http://www.gnu.org/licenses/>.

*/

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include "ar0234.h"

//字符设备结构体
struct i2c_dev
{
	dev_t devid;	                //设备号
	int major;		                //主设备号
	int minor;		                //副设备号
	struct cdev cdev;               //字符设备结构体
	struct class *class;            //设备类
	struct device *device;          //设备实例
	struct device_node *node, *cam_node, *led_node;
	int cam_emio[2];	            //相机复位和触发信号引脚
	int led_gpio;                   //LED引脚
	void *private_data;             //私有数据，用来保存probe函数传递进来的i2c_client结构体
};

#define DEVICE_COUNT 1
#define DEVICE_NAME "ar0234"

#define CAMERA_RESET 0
#define CAMERA_TRIGGER 1

// 定义IOCTL相关命令
#define IOCTL_AR0234_EXPOSURE_TIME  _IOW('a',0x1,u16)
#define IOCTL_AR0234_ANALOG_GAIN  _IOW('a',0x2,u16)
#define IOCTL_AR0234_RED_GAIN  _IOW('a',0x3,uint16_t)
#define IOCTL_AR0234_BLUE_GAIN  _IOW('a',0x4,uint16_t)
#define IOCTL_AR0234_GR_GB_GAIN  _IOW('a',0x5,uint16_t)

// #define USE_TRIGGER_FUNCTION 

char writebuf[5];
struct i2c_dev ar0234;

// 函数声明
int ar0234_probe(struct i2c_client *client, const struct i2c_device_id *id);
int ar0234_remove(struct i2c_client *client);
//读取ar0234多个寄存器数据
static int ar0234_read_regs(struct i2c_dev *dev, u16 reg, void *val, int len)
{
	int ret = 0;
	struct i2c_client *client = (struct i2c_client *)dev->private_data;
	struct i2c_msg msg[2];
	u8 reg_buf[2];					  //将16位地址拆分成两个8位
	reg_buf[0] = (reg & 0xff00) >> 8; //高八位
	reg_buf[1] = reg & 0x00ff;		  //低八位
	//配置struct i2c_msg *msgs，msg[0]为发送要读取的寄存器首地址
	msg[0].addr = client->addr;       //从机地址，也就是EEPROM地址
	msg[0].flags = 0;			      //0为向从机进行写操作
	msg[0].buf = reg_buf;		      //buf为要发送的数据，先发送要进行读操作读寄存器地址
	msg[0].len = 2;				      //寄存器地址的长度为1
	//配置struct i2c_msg *msgs，msg[1]发送要读取的寄存器首地址
	msg[1].addr = client->addr;       //从机地址，也就是EEPROM地址
	msg[1].flags = I2C_M_RD;	      //向从机进行读操作
	msg[1].buf = val;			      //从从机读取的数据保存到val里
	msg[1].len = len;			      //从从机读取的数据长度,寄存器为16位
	//i2c_transfer可以对寄存器进行读和写，需要对struct i2c_msg *msgs进行配置实现读或者写数据
	ret = i2c_transfer(client->adapter, msg, 2);
	if (ret != 2)
	{
		printk("%s %s %d ar0234 read regs fail\r\n",__FILE__,__FUNCTION__,__LINE__);
		return -1;
	}
	return ret;
}

//读取ar0234某个寄存器数据
static int ar0234_read_reg(struct i2c_dev *dev, u16 reg, void *val)
{
	int ret = 0;
	ret = ar0234_read_regs(dev, reg, val, 2); //寄存器为16位，len要置为2
	return ret;
}

//向ar0234的某些寄存器写数据
static int ar0234_write_regs(struct i2c_dev *dev, u16 reg, u16 buf, int len)
{
	u8 b[256];
	int ret = 0;
	struct i2c_client *client = (struct i2c_client *)dev->private_data;
	struct i2c_msg msg;
	//将16位地址拆分成两个8位
	b[0] = (reg & 0xff00) >> 8; //高八位
	b[1] = reg & 0x00ff;		//低八位					//数据首位为寄存器地址
	b[2] = (buf & 0xff00) >> 8; //高八位
	b[3] = buf & 0x00ff;		//低八位
	//配置struct i2c_msg *msgs
	msg.addr = client->addr;    //从机地址，也就是EEPROM地址
	msg.flags = 0;			    //0为向从机进行写操作
	msg.buf = b;			    //buf为要发送的数据，实际数据+寄存器地址
	msg.len = 2 + len;		    //要发送的数据长度：实际数据长度+寄存器地址长度
	ret = i2c_transfer(client->adapter, &msg, 1);
	if (ret != 1)
	{
		printk("%s %s %d ar0234 write regs fail\r\n",__FILE__,__FUNCTION__,__LINE__);
		return -1;
	}
	return ret;
}

//向ar0234的某个寄存器写数据
static int ar0234_write_reg(struct i2c_dev *dev, u16 reg, u16 data)
{
	int ret = 0;
	ret = ar0234_write_regs(dev, reg, data, 2); //寄存器为16位，len要置为2
	return ret;
}

//初始化ar0234寄存器参数
static int sensor_init(struct i2c_dev *dev)
{
	int ret = 0;
	char sensor_id[2];
    // 读取相机ID,AR0234的ID为0x0A56,AR0144的ID为0x0056
	ar0234_read_regs(&ar0234, 0x3000, &sensor_id[0], 1);
	ar0234_read_regs(&ar0234, 0x3001, &sensor_id[1], 1);
	if (sensor_id[0] != 0x0A || sensor_id[1] != 0x56)
	{
        printk("%s %s %d  Not AR0234 id, %x %x\r\n",__FILE__,__FUNCTION__,__LINE__,sensor_id[0], sensor_id[1]);
		goto error_id;
	}
	else
	{
		printk("Got AR0234 id, %x %x\r\n", sensor_id[0], sensor_id[1]);
	}
    // 刷写相机寄存器参数
	int i = 0;
	while (AR0234_NO_AE[i].reg != SEQUENCE_END)
	{
		ret = ar0234_write_reg(dev, AR0234_NO_AE[i].reg, AR0234_NO_AE[i].val);
		if (ret < 0)
		{
            printk("%s %s %d register 0x%04X write fail!\r\n",__FILE__,__FUNCTION__,__LINE__,AR0234_NO_AE[i].reg);
			goto fail_write;
		}
		i++;
	}
	return 0;
fail_write:
error_id:
	return -1;
}

static int ar0234_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &ar0234;
	return 0;
}

static long ar0234_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
	struct i2c_dev *dev = file->private_data;

	u16 data;
	char buf[2];
	switch (cmd)
	{
	case IOCTL_AR0234_EXPOSURE_TIME:
		if (copy_from_user(&data, (void __user *)arg, sizeof(u16))){
			printk("%s %s %d copy_from_user fail\r\n",__FILE__,__FUNCTION__,__LINE__);
			return -EFAULT;
		}
		printk("ioctl set exposure_time is:%x\r\n", data);
		if (ar0234_write_reg(&ar0234, 0x3012, data) < 0){
			printk("%s %s %d register 0x3012 write fail!\r\n",__FILE__,__FUNCTION__,__LINE__);
			return -EFAULT;
		}
		ar0234_read_regs(&ar0234, 0x3012, &buf[0], 1);
		ar0234_read_regs(&ar0234, 0x3013, &buf[1], 1);
		printk("get exposure_time is:%x\r\n", (buf[0] << 8) | buf[1]);
		break;
	case IOCTL_AR0234_ANALOG_GAIN:
		if (copy_from_user(&data, (void __user *)arg, sizeof(u16))){
			return -EFAULT;
		}
		printk("ioctl set analog_gain is:%x\r\n", data);
		if (ar0234_write_reg(&ar0234, 0x3060, data) < 0){
			return -EFAULT;
		}
		ar0234_read_regs(&ar0234, 0x3060, &buf[0], 1);
		ar0234_read_regs(&ar0234, 0x3061, &buf[1], 1);
		printk("get analog_gain is:%x\r\n", (buf[0] << 8) | buf[1]);
		break;
	case IOCTL_AR0234_RED_GAIN:
		if (copy_from_user(&data, (void __user *)arg, sizeof(u16))){
			return -EFAULT;
		}
		printk("ioctl set red_gain is:%x\r\n", data);
		if (ar0234_write_reg(&ar0234, 0x305A, data) < 0){
			return -EFAULT;
		}
		ar0234_read_regs(&ar0234, 0x305A, &buf[0], 1);
		ar0234_read_regs(&ar0234, 0x305B, &buf[1], 1);
		printk("get RED_gain is:%x\r\n", (buf[0] << 8) | buf[1]);
		break;
	case IOCTL_AR0234_BLUE_GAIN:
		if (copy_from_user(&data, (void __user *)arg, sizeof(u16))){
			return -EFAULT;
		}
		printk("ioctl set blue_gain is:%x\r\n", data);
		if (ar0234_write_reg(&ar0234, 0x3058, data) < 0){
			return -EFAULT;
		}
		ar0234_read_regs(&ar0234, 0x3058, &buf[0], 1);
		ar0234_read_regs(&ar0234, 0x3059, &buf[1], 1);
		printk("get BLUE_gain is:%x\r\n", (buf[0] << 8) | buf[1]);
		break;
	case IOCTL_AR0234_GR_GB_GAIN:
		if (copy_from_user(&data, (void __user *)arg, sizeof(u16))){
			return -EFAULT;
		}
		printk("ioctl set gr_gb_gain is:%x\r\n", data);
		if (ar0234_write_reg(&ar0234, 0x3056, data) < 0){
			return -EFAULT;
		}
		if (ar0234_write_reg(&ar0234, 0x305C, data) < 0){
			return -EFAULT;
		}
		ar0234_read_regs(&ar0234, 0x305C, &buf[0], 1);
		ar0234_read_regs(&ar0234, 0x305D, &buf[1], 1);
		printk("get GREEN_gain is:%x\r\n", (buf[0] << 8) | buf[1]);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}
static int ar0234_release(struct inode *inode, struct file *filp)
{
	filp->private_data = NULL;
	printk("ar0234 release!\r\n");
	return 0;
}



static const struct file_operations ar0234_fops = {
	.owner = THIS_MODULE,
	.open = ar0234_open,
	.release = ar0234_release,
	.unlocked_ioctl = ar0234_ioctl,
};


static int ar0234_init(struct i2c_dev *dev)
{
	int ret = 0;
	//1.创建字符设备号
	dev->major = 0;
	if (dev->major) //给定设备号
	{
		dev->devid = MKDEV(dev->major, 0);
		ret = register_chrdev_region(dev->devid, DEVICE_COUNT, DEVICE_NAME);
	}
	else
	{
		ret = alloc_chrdev_region(&dev->devid, 0, DEVICE_COUNT, DEVICE_NAME);
	}
	if (ret < 0)
	{
        printk("%s %s %d fail to register chardev!\r\n",__FILE__,__FUNCTION__,__LINE__);
		goto fail_register;
	}
	dev->major = MAJOR(dev->devid);
	dev->minor = MINOR(dev->devid);
	printk("ar0234 MAJOR = %d, MINOR = %d\r\n", dev->major, dev->minor);

	//2.添加字符设备
	dev->cdev.owner = THIS_MODULE;
	cdev_init(&dev->cdev, &ar0234_fops);
	ret = cdev_add(&dev->cdev, dev->devid, DEVICE_COUNT);
	if (ret < 0)
	{
        printk("%s %s %d fail to add chardev!\r\n",__FILE__,__FUNCTION__,__LINE__);
		goto fail_cdev;
	}

	//3.自动创建设备节点
	dev->class = class_create(THIS_MODULE, DEVICE_NAME); //创建类
	if (IS_ERR(dev->class))
	{
        printk("%s %s %d fail to create class!\r\n",__FILE__,__FUNCTION__,__LINE__);
		goto fail_class;
	}
	dev->device = device_create(dev->class, NULL, dev->devid, NULL, DEVICE_NAME); //创建设备
	if (IS_ERR(dev->device))
	{
        printk("%s %s %d fail to create device!\r\n",__FILE__,__FUNCTION__,__LINE__);
		goto fail_device;
	}

	//5.从设备树中获取camera所对应的GPIO
	dev->cam_node = of_find_compatible_node(NULL, NULL, "ar0234");
	dev->cam_emio[CAMERA_RESET] = of_get_named_gpio(dev->cam_node, "CAM0_EMIO", 0);
	if (dev->cam_emio[CAMERA_RESET] < 0)
	{
        printk("%s %s %d fail to get CAMERA_RESET GPIO name!\r\n",__FILE__,__FUNCTION__,__LINE__);
		goto fail_get_name;
	}
    printk("cam_emio[CAMERA_RESET] = %d\r\n", dev->cam_emio[CAMERA_RESET]);

    #ifdef USE_TRIGGER_FUNCTION
	dev->cam_emio[CAMERA_TRIGGER] = of_get_named_gpio(dev->cam_node, "CAM_Trigger", 0);
	if (dev->cam_emio[CAMERA_TRIGGER] < 0)
	{
        printk("%s %s %d fail to get CAMERA_TRIGGER GPIO name!\r\n",__FILE__,__FUNCTION__,__LINE__);
		goto fail_get_name;
	}
    printk("cam_emio[CAMERA_TRIGGER] = %d\r\n", dev->cam_emio[CAMERA_TRIGGER]);
    #endif

	//6.申请IO, 使用GPIO
	ret = gpio_request(dev->cam_emio[CAMERA_RESET], "cam_reset_gpio");
	if (ret < 0)
	{
        printk("%s %s %d fail to request CAMERA_RESET gpio!\r\n",__FILE__,__FUNCTION__,__LINE__);
		goto fail_gpio_request;
	}
	
	ret = gpio_direction_output(dev->cam_emio[CAMERA_RESET], 0); //设置IO为输出，默认为0低电平复位
	if (ret < 0)
	{
		goto fail_set_output;
	}

    #ifdef USE_TRIGGER_FUNCTION
	ret = gpio_request(dev->cam_emio[CAMERA_TRIGGER], "cam_trigger_gpio");
	if (ret < 0)
	{
        printk("%s %s %d fail to request CAMERA_TRIGGER gpio!\r\n",__FILE__,__FUNCTION__,__LINE__);
		goto fail_gpio_request;
	}
	ret = gpio_direction_output(dev->cam_emio[CAMERA_TRIGGER], 0); //设置IO为输出，默认为1高电平触发
	if (ret < 0)
	{
		goto fail_set_output;
	}
    #endif

	printk("ar0234 init!\r\n");
	return 0;

fail_set_output:
	gpio_free(dev->cam_emio[CAMERA_RESET]);
    #ifdef USE_TRIGGER_FUNCTION
	gpio_free(dev->cam_emio[CAMERA_TRIGGER]);
    #endif
fail_gpio_request:
fail_get_name:
	device_destroy(dev->class, dev->devid);
fail_device:
	class_destroy(dev->class);
fail_class:
	cdev_del(&dev->cdev);
fail_cdev:
	unregister_chrdev_region(dev->devid, DEVICE_COUNT);
fail_register:
    printk("%s %s %d ar0234fail to init!\r\n",__FILE__,__FUNCTION__,__LINE__);
	return -1;
}

static void ar0234_exit(struct i2c_dev *dev)
{
	gpio_set_value(dev->cam_emio[CAMERA_RESET], 0);
	gpio_free(dev->cam_emio[CAMERA_RESET]);
    #ifdef USE_TRIGGER_FUNCTION
	gpio_set_value(dev->cam_emio[CAMERA_TRIGGER], 0);
	gpio_free(dev->cam_emio[CAMERA_TRIGGER]);
    #endif
	device_destroy(dev->class, dev->devid);				//摧毁设备
	class_destroy(dev->class);							//摧毁类
	cdev_del(&dev->cdev);								//注销字符设备
	unregister_chrdev_region(dev->devid, DEVICE_COUNT); //注销字符设备号
	printk("ar0234 exit!\r\n");
}

static struct of_device_id ar0234_of_match[] = {
	{.compatible = "ar0234"},
	{/* Sentinel*/},
};

static struct i2c_driver ar0234_i2c_driver = {
	.probe = ar0234_probe,
	.remove = ar0234_remove,
	.driver = {
		.name = "ar0234",
		.owner = THIS_MODULE,
		.of_match_table = ar0234_of_match,
	},

};
//当probe函数执行后，probe函数传递的第一个变量struct i2c_client *client，它是驱动和设备匹配之后系统分配的i2c_client结构体，用来表示具体的设备
//i2c_client有个成员变量struct i2c_adapter *adapter，保存了此i2c设备所对应的i2c适配器
int ar0234_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret = 0;
	//获取设备树节点
	ar0234.node = client->dev.of_node;
	if (IS_ERR(ar0234.node))
	{
		printk("fail to find node!\r\n");
        printk("%s %s %d fail to find node!\r\n",__FILE__,__FUNCTION__,__LINE__);
		goto fail_find_node;
	}
	//搭建字符设备框架，在/dev/下创建文件
	ar0234_init(&ar0234);
	ar0234.private_data = client; //将i2c_client结构体保存到设备结构体的私有数据中
	//复位相机
	gpio_set_value(ar0234.cam_emio[CAMERA_RESET], 0);
	msleep(5);
	gpio_set_value(ar0234.cam_emio[CAMERA_RESET], 1);
	ssleep(1);
	ret = sensor_init(&ar0234);
	if (ret < 0)
	{
		goto fail_init;
	}
	char value[2];
    //读取相机图像尺寸起始地址
	ar0234_read_reg(&ar0234, 0x3002, value);
	printk("reg 0x3002 =%x %x\r\n", value[0], value[1]);
	ar0234_read_reg(&ar0234, 0x3004, value);
	printk("reg 0x3004 =%x %x\r\n", value[0], value[1]);
	ar0234_read_reg(&ar0234, 0x301C, value);
	printk("reg 0x301C =%x %x\r\n", value[0], value[1]);


	return 0;
fail_init:
    printk("%s %s %d sensor_init fail\r\n",__FILE__,__FUNCTION__,__LINE__);
fail_find_node:
	return -1;
}

//驱动移除函数
int ar0234_remove(struct i2c_client *client)
{
	ar0234_exit(&ar0234);
	return 0;
}

//驱动入口函数
static int __init i2c_dev_init(void)
{
	i2c_add_driver(&ar0234_i2c_driver);
	return 0;
}

//驱动出口函数
static void __exit i2c_dev_exit(void)
{
	i2c_del_driver(&ar0234_i2c_driver);
}

module_init(i2c_dev_init);
module_exit(i2c_dev_exit);

/* 驱动描述信息 */
MODULE_AUTHOR("LONGMEN");
MODULE_LICENSE("GPL");